﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace WinEnvBack
{
    static class AsConsole
    {
        static string[] Args;

        static bool Cancel = false;

        internal static void Run(string[] args)
        {
            Console.WriteLine("WinEnvBack Initializing...");
            ConsoleColor defaultColor = Console.ForegroundColor;
            Console.ForegroundColor = ConsoleColor.Green;
            Console.WriteLine("powered by Heroius");
            Console.ForegroundColor = defaultColor;

            if (args.Count() > 0)
            {
                Args = args;
                GoSwitch();
                return;//quit if running with params
            }
            else
            {
                while (!Cancel)
                {
                    Console.WriteLine("\nInput command:");
                    Args = Console.ReadLine().Split(' ');
                    GoSwitch();
                }
            }
        }

        static string[] SperateParams(string CommandText)
        {
            List<string> Params = new List<string>();
            bool IsInWord = false;
            bool IsWithQuote = false;
            List<char> Word = new List<char>();

            for (int i = 0; i < CommandText.Length; i++)
            {
                if (IsInWord)
                {
                    if (CommandText[i] == ' ')
                    {
                        if (IsWithQuote)
                        { Word.Add(CommandText[i]); }
                        else
                        {
                            IsInWord = false;
                            Params.Add(new string(Word.ToArray()));
                        }
                    }
                    else if (CommandText[i] == '\"')
                    {
                        if (i == CommandText.Length - 1 || CommandText[i + 1] == ' ')
                        {
                            IsInWord = false;
                            Params.Add(new string(Word.ToArray()));
                            IsWithQuote = false;
                        }
                        else Word.Add(CommandText[i]);
                    }
                    else
                    {
                        Word.Add(CommandText[i]);
                        if (i == CommandText.Length - 1)
                        {
                            IsInWord = false;
                            Params.Add(new string(Word.ToArray()));
                        }
                    }
                }
                else
                {
                    if (CommandText[i] == ' ') continue;
                    else if (CommandText[i] == '\"')
                    {
                        IsInWord = true;
                        Word.Clear();
                        IsWithQuote = true;
                    }
                    else
                    {
                        if (i == CommandText.Length - 1)
                        {
                            Params.Add(CommandText[i].ToString());
                        }
                        else
                        {
                            IsInWord = true;
                            Word.Clear();
                            IsWithQuote = false;
                            Word.Add(CommandText[i]);
                        }
                    }
                }
            }
            return Params.ToArray();
        }

        static void GoSwitch()
        {
            switch (Args[0])
            {
                case "-ms":
                    MergePath(Args[1], EnvironmentVariableTarget.Machine);
                    Console.WriteLine("Path variable is merged.");
                    break;
                case "-mu":
                    MergePath(Args[1], EnvironmentVariableTarget.User);
                    Console.WriteLine("Path variable is merged.");
                    break;
                case "-m"://overwrite current set with restored one
                    MergePath(Args[1], EnvironmentVariableTarget.Machine);
                    MergePath(Args[2], EnvironmentVariableTarget.User);
                    Console.WriteLine("Path variable is merged.");
                    break;
                case "-rs":
                    RecoverEnv(Args[1], EnvironmentVariableTarget.Machine);
                    Console.WriteLine("Environment variables are overwritten.");
                    break;
                case "-ru":
                    RecoverEnv(Args[1], EnvironmentVariableTarget.User);
                    Console.WriteLine("Environment variables are overwritten.");
                    break;
                case "-r"://overwrite current set with restored one
                    RecoverEnv(Args[1], EnvironmentVariableTarget.Machine);
                    RecoverEnv(Args[2], EnvironmentVariableTarget.User);
                    Console.WriteLine("Environment variables are overwritten.");
                    break;
                case "-cs":
                    CreateEnv(Args[1], EnvironmentVariableTarget.Machine);
                    Console.WriteLine("Restore file is updated.");
                    break;
                case "-cu":
                    CreateEnv(Args[1], EnvironmentVariableTarget.User);
                    Console.WriteLine("Restore file is updated.");
                    break;
                case "-c"://create a backup of current set
                    CreateEnv(Args[1], EnvironmentVariableTarget.Machine);
                    CreateEnv(Args[2], EnvironmentVariableTarget.User);
                    Console.WriteLine("Restore file is updated.");
                    break;
                case "exit":
                case "quit":
                case "close":
                case "return":
                case "shut":
                    Cancel = true;
                    return;
                default:
                    Console.WriteLine("invalid param");
                    return;
            }
            Console.WriteLine("Operation done.");
            return;
        }

        //merge: 合并环境中的PATH变量

        internal static void MergePath(string arg, EnvironmentVariableTarget tar)
        {
            var stream = File.Open(arg, FileMode.Open, FileAccess.Read);
            var sysenv = (SerializableDictionary<string, string>)Program.xmler.Deserialize(stream);
            stream.Close();
            string[] rpaths = sysenv["Path"].Split(';');
            StringBuilder sbcp = new StringBuilder(Environment.GetEnvironmentVariable("Path", tar));
            string[] cpaths = sbcp.ToString().Split(';');
            foreach (var item in rpaths)
            {
                if (!cpaths.Contains(item))
                {
                    sbcp.Append(';');
                    sbcp.Append(item);
                }
            }
            Environment.SetEnvironmentVariable("Path", sbcp.ToString(), EnvironmentVariableTarget.Machine);
        }

        internal static void RecoverEnv(string arg, EnvironmentVariableTarget tar)
        {
            var stream = File.Open(arg, FileMode.Open, FileAccess.Read);
            var sysenv = (SerializableDictionary<string, string>)Program.xmler.Deserialize(stream);
            stream.Close();
            foreach (var item in sysenv)
            {
                Environment.SetEnvironmentVariable(item.Key, item.Value, tar);
            }
        }

        internal static void CreateEnv(string arg, EnvironmentVariableTarget tar)
        {
            var sysenv = new SerializableDictionary<string, string>();
            IDictionary vars = Environment.GetEnvironmentVariables(tar);
            var keys = vars.Keys.Cast<string>();
            var vals = vars.Values.Cast<string>();
            for (int i = 0; i < vars.Count; i++)
            {
                sysenv.Add(keys.ElementAt(i), vals.ElementAt(i));
            }
            var stream = File.Open(arg, FileMode.Create, FileAccess.ReadWrite);
            Program.xmler.Serialize(stream, sysenv);
            stream.Close();
        }
    }
}
